package com.mybpm.core.instance

import com.easecurity.core.basis.UserDo
import com.easecurity.core.basis.b.User
import com.easecurity.core.basis.b.UserInfo
import com.mybpm.core.BpmUserService
import com.mybpm.core.definition.Process
import com.mybpm.core.definition.ProcessLoadService
import com.mybpm.core.definition.Transition
import com.mybpm.core.definition.XmlNode
import com.mybpm.core.definition.XmlProcess
import com.mybpm.core.definition.XmlTransition
import com.mybpm.core.vo.Candidate
import com.mybpm.core.vo.TaskSubmit
import grails.gorm.transactions.Transactional
import org.slf4j.Logger
import org.slf4j.LoggerFactory
import org.springframework.beans.factory.annotation.Autowired
import org.springframework.stereotype.Service

@Service
public class TaskService {
    private static final Logger log = LoggerFactory.getLogger(TaskService.class)

    @Autowired
    ProcessLoadService processLoadService
    @Autowired
    com.mybpm.core.ProcessScriptService processScriptService
    @Autowired
    BpmUserService userService

    /**
     * 启动流程
     *
     * @param processId 流程定义id
     * @param userDo 首环节处理人（起草人）
     * @param form 表单信息
     */
    @Transactional
    public ToDoTask startProcess(String processId, UserDo userDo, Map form = null) {
        log.debug("----------startProcess")
        XmlProcess process = processLoadService.getXmlProcess(processId)
        XmlNode start = processLoadService.getStartNode(processId)
        ProcessInstance processInst = new ProcessInstance(pid: process.id, displayName: process.displayName ?: process.name, type: process.type, revision: process.version)
        processInst.process = Process.findByPid(process.id)
        if (userDo) {
            processInst.createrId = userDo.user.id
            processInst.createrName = userDo.userinfo?.name
        }
        processInst.save()
        List<ToDoTask> toDoTask = submit(processInst, null, null, start, [userDo], start.transitions[0].toNode, [start.transitions[0]], form)
        // TODO 在草稿或者待办中？
        return toDoTask[0]
    }

    /**
     * 启动流程并获取后续环节的候选人
     *
     * @param processId 流程定义id
     * @param userDo 首环节处理人（起草人）
     * @param form 表单信息
     */
    public Map startProcessWithCandidates(String processId, UserDo userDo, Map form) {
        log.debug("----------startProcessWithCandidates")
        ToDoTask toDoTask = startProcess(processId, userDo, form)
        Candidate candidate = getNextCandidates(toDoTask, userDo, form)
        return [task: toDoTask, candidate: candidate]
    }

    /**
     * 获取候选人、环节及路径列表
     *
     * @param task 当前任务
     * @param userDo 当前登录人
     * @param form 表单信息
     */
    public Candidate getNextCandidates(ToDoTask task, UserDo userDo, Map form = null) {
        // TODO 判断actor是否为fromTask的所有者
        if (true) {

        } else throw new RuntimeException("非法任务所有者")

        XmlNode node = processLoadService.getXmlNode(task.pid, task.nid)
        Candidate candidate = new Candidate()
        candidate.nodeList = []
        candidate.isRadio = true
        // TODO 先不考虑多级路径（中间有网关）的情况
        node.transitions.each { it ->
            // TODO 判断路径是否可用
            if (true) {
                XmlNode toNode = it.toNode
                // TODO 判断环节是否可用
                if (true) {
                    Candidate.Node n = new Candidate.Node()
                    n.id = toNode.id
                    n.name = toNode.displayName ?: toNode.name
                    n.tid = it.id
                    n.tname = it.displayName ?: it.name
                    if ('node'.equals(toNode.type)) {
                        n.userList = []
                        n.isRadio = true
                        // 路径上有候选人时，优先使用路径的上的
                        def users
                        if (it.actor) {
                            users = processScriptService.eval(it.actor, form, task.processInstance, task)
                        } else {
                            users = processScriptService.eval(toNode.actor, form, task.processInstance, task)
                        }
                        if (users) {
                            if (!(users instanceof List)) users = [users]
                            for (def user : users) {
                                Candidate.User u = new Candidate.User()
                                u.id = user.user.id
                                u.name = user.userinfo?.name
                                // TODO 职务待完成
//                            u.postsName = user.orgUsers?.first()
                                n.userList.add(u)
                            }
                        }
                    }
                    candidate.nodeList.add(n)
                }
            }
        }
        return candidate
    }

    /**
     * 提交下一步处理
     *
     * @param task 当前任务
     * @param userDo 当前登录人
     * @param nextNodeList 后续环节及处理人信息
     * @param form 表单信息
     */
    public Map submit2Next(ToDoTask task, UserDo sender, List<TaskSubmit.Node> nextNodeList, Map form) {
        List toDoTasks = []
        // 简单的生成代办
        nextNodeList.each { TaskSubmit.Node nextNode ->
            XmlNode fromNode = processLoadService.getXmlNode(task.pid, task.nid)
            String nodeId = nextNode.id ?: processLoadService.nodeName2Id(task.pid, nextNode.name)
            XmlNode toNode = processLoadService.getXmlNode(task.pid, nodeId)
            // 路径
            List<XmlTransition> transitions = null
            if (nextNode.tid) {
                transitions = []
                nextNode.tid.split(",").each {
                    transitions.add(processLoadService.getXmlTransition(task.pid, it))
                }
            } else if (nextNode.tname) {
                transitions = []
                nextNode.tname.split(",").each {
                    transitions.add(processLoadService.getXmlTransition(task.pid, processLoadService.transitionName2Id(task.pid, it)))
                }
            }
            if ("end".equals(toNode.type)) {  // TODO 结束环节
                submit2End(task.processInstance, task, sender, fromNode, toNode, transitions, form)
            } else {  // 普通环节
                List<UserDo> actor = []
                // 待办人
                if (nextNode.users) {
                    nextNode.users.each {
                        UserDo ud = userService.getUserDo(it.id)
                        if (!ud) {
                            ud = new UserDo()
                            User u = new User()
                            u.id = it.id
                            ud.user = u
                            UserInfo ui = new UserInfo()
                            ui.name = it.name
                            ud.userinfo = ui
                        }
                        actor.add(ud)
                    }
                }
                List<ToDoTask> dts = submit(task.processInstance, task, sender, fromNode, actor, toNode, transitions, form)
                toDoTasks.addAll(dts)
            }
        }
        // TODO 待阅待开发

        // 待办转已办
        task.delete()
        DoneTask doneTask = new DoneTask();
        doneTask.properties = task.properties
        doneTask.save()
        return [toDoTasks: toDoTasks, toReadTasks: []]
    }

    // TODO 一个环节，简单的生成代办
    private List<ToDoTask> submit(ProcessInstance processInst, ToDoTask fromTask, UserDo sender, XmlNode fromNode, List<UserDo> actor, XmlNode toNode, List<XmlTransition> transitions, Map form = null) {
        // TODO 判断sender是否为fromTask的所有者
        if (true) {

        } else throw new RuntimeException("非法任务所有者")

        // TODO 判断actor是否在toNode的候选人列表中 ？？？我们是流程引擎，不用这么搞了吧，或者如果候选人为特殊标识时，跳过（例如，不配置actor）
        if (true) {

        } else throw new RuntimeException("非法代办人")

        // TODO 判断路径可用性
        if (true) {

        } else throw new RuntimeException("非法路径")

        // TODO 判断环节可用性
        if (true) {

        } else throw new RuntimeException("非法环节")

        if (actor) {
            List toDoTasks = []
            actor.each {
                ToDoTask toDoTask = new ToDoTask(processInstance: processInst, pid: processInst.pid, nid: toNode.id, displayName: toNode.displayName ?: toNode.name)
                if (fromTask) toDoTask.formTaskId = fromTask.id
                if (sender) {
                    toDoTask.senderId = sender.user.id
                    toDoTask.senderName = sender.userinfo?.name
                }
                toDoTask.actorId = it.user.id
                toDoTask.actorName = it.userinfo?.name
                if (transitions) {
                    toDoTask.transitions = Transition.findAllByTidInList(transitions*.id)
                }
                // TODO 待办标题处理
                toDoTask.title = toDoTask.displayName
                toDoTask.save()
                toDoTasks.add(toDoTask)
            }
            return toDoTasks
        }
    }

    /**
     * 提交结束
     *
     * @param processInst
     * @param fromTask
     * @param sender
     * @param fromNode
     * @param toNode
     * @param transitions
     * @param form
     * @return
     */
    private DoneTask submit2End(ProcessInstance processInst, ToDoTask fromTask, UserDo sender, XmlNode fromNode, XmlNode toNode, List<XmlTransition> transitions, Map form = null) {
        // TODO 判断sender是否为fromTask的所有者
        if (true) {

        } else throw new RuntimeException("非法任务所有者")

        // TODO 判断路径可用性
        if (true) {

        } else throw new RuntimeException("非法路径")

        DoneTask doneTask = new DoneTask(processInstance: processInst, pid: processInst.pid, nid: toNode.id, displayName: toNode.displayName ?: toNode.name)
        if (fromTask) doneTask.formTaskId = fromTask.id
        if (sender) {
            doneTask.senderId = sender.user.id
            doneTask.senderName = sender.userinfo?.name
        }
        if (transitions) {
            doneTask.transitions = Transition.findAllByTidInList(transitions*.id)
        }
        doneTask.save()
        // TODO 判断流程是否结束，并处理流程信息
        return doneTask
    }
}